package cn.edu.xmu.oomall.payment.service;

import cn.edu.xmu.oomall.core.util.JacksonUtil;
import cn.edu.xmu.oomall.core.util.ReturnObject;
import cn.edu.xmu.oomall.payment.dao.ErrorAccountDao;
import cn.edu.xmu.oomall.payment.dao.OrderDao;
import cn.edu.xmu.oomall.payment.dao.PaymentDao;
import cn.edu.xmu.oomall.payment.dao.RefundDao;
import cn.edu.xmu.oomall.payment.microservice.AlipayService;
import cn.edu.xmu.oomall.payment.microservice.WechatpayService;
import cn.edu.xmu.oomall.payment.microservice.bo.NotifyBody;
import cn.edu.xmu.oomall.payment.microservice.bo.WeChatPayTransaction;
import cn.edu.xmu.oomall.payment.microservice.vo.*;
import cn.edu.xmu.oomall.payment.model.bo.*;
import cn.edu.xmu.oomall.payment.model.po.PaymentPatternPoExample;
import cn.edu.xmu.oomall.payment.model.po.PaymentPo;
import cn.edu.xmu.oomall.payment.model.po.PaymentPoExample;
import cn.edu.xmu.oomall.payment.model.vo.*;
import cn.edu.xmu.oomall.payment.util.AlipayConfig;
import cn.edu.xmu.oomall.payment.util.PaymentReturnNo;
import cn.edu.xmu.oomall.payment.util.PaymentReturnObject;
import cn.edu.xmu.privilegegateway.annotation.util.Common;
import cn.edu.xmu.privilegegateway.annotation.util.InternalReturnObject;
import cn.edu.xmu.privilegegateway.annotation.util.ReturnNo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

import static cn.edu.xmu.privilegegateway.annotation.util.Common.cloneVo;

@Service
public class PaymentService {
    @Autowired
    private PaymentDao paymentDao;
    @Autowired
    private RefundDao refundDao;
    @Autowired
    private ErrorAccountDao errorAccountDao;
    @Autowired
    private WechatpayService wechatpayService;
    @Autowired
    private AlipayService alipayService;
    @Autowired
    private OrderDao orderDao;

    //微信支付状态
    private static final String TRADE_STATE_SUCCESS = String.format("SUCCESS");
    private static final String TRADE_STATE_FAIL = String.format("NOTPAY");
    private static final String TRADE_STATE_CLOSE = String.format("CLOSED");
    private static final String TRADE_STATE_REFUND = String.format("REFUND");
    private static final String REFUND_STATUS_SUCCESS = String.format("SUCCESS");
    private static final String REFUND_STATUS_FAIL = String.format("ABNORMAL");

    //阿里支付状态
    private static final Byte TRADE_SUCCESS = 1;
    private static final Byte WAIT_BUYER_PAY = 2;

    private static final int WECHAT = 1;
    private static final int ALI = 0;

    /**
     * 顾客支付已建立的支付单
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject updatePayment(Long id, PaymentPatternVo patternVo, Long userId, String userName) {
        Payment payment = (Payment) paymentDao.selectPaymentById(id).getData();
        if (payment == null) {
            return new ReturnObject(ReturnNo.RESOURCE_ID_NOTEXIST);
        }
        //未支付状态
        if (!payment.getState().equals(Payment.State.OBLIGATION.getCode()))
            return new ReturnObject(ReturnNo.STATENOTALLOW);
        payment.setPatternId(patternVo.getPayPattern().longValue());
        payment.setPayTime(LocalDateTime.now());
        Common.setPoModifiedFields(payment, userId, userName);
        ReturnObject paymentRet = paymentDao.updatePayment(payment);
        SimplePaymentVo simplePaymentVo = cloneVo(payment, SimplePaymentVo.class);
        //根据渠道选择统一下单接口
        if (patternVo.getPayPattern() == WECHAT) {
            WeChatPayTransactionVo weChatPayTransactionVo = getWeChatPayVo(payment.getAmount().intValue());
            wechatpayService.createTransaction(weChatPayTransactionVo);
        } else if (patternVo.getPayPattern() == ALI) {
            AliPayVo aliPayVo = new AliPayVo(payment.getTradeSn(), payment.getAmount());
            String bizContent = JacksonUtil.toJson(aliPayVo);
            alipayService.gatewayDo(AlipayConfig.APP_ID, "alipay.trade.wap.pay", AlipayConfig.FORMAT,
                    AlipayConfig.CHARSET, AlipayConfig.SIGN_TYPE, AlipayConfig.SIGN, AlipayConfig.TIMESTAMP, AlipayConfig.NOTIFY_URL, bizContent);
        }
        return new ReturnObject(paymentRet.getCode(), paymentRet.getErrmsg(), simplePaymentVo);
    }

    /**
     * 顾客支付
     * 生成支付单，微信返回微信预付单标识
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject createPayment(PaymentVo paymentVo, Long userId, String userName) {
        Payment payment = cloneVo(paymentVo, Payment.class);
        //生成贸易单号
        Random r = new Random();
        int platform = Math.abs(r.nextInt(36));
        String tradeSn = Common.genSeqNum(platform);
        payment.setTradeSn(tradeSn);
        payment.setState(Payment.State.OBLIGATION.getCode());
        Common.setPoCreatedFields(payment, userId, userName);
        ReturnObject paymentRet = paymentDao.insertPayment(payment);
        if (paymentRet.getCode().getCode() != 0) {
            return paymentRet;
        }
        PrePaymentRetVo prePaymentRetVo = cloneVo(payment, PrePaymentRetVo.class);
        //调用统一下单接口
        if (paymentVo.getPatternId() == WECHAT) {
            WeChatPayTransactionVo weChatPayTransactionVo = getWeChatPayVo(payment.getAmount().intValue());
            InternalReturnObject wechatRetObj = wechatpayService.createTransaction(weChatPayTransactionVo);
            if (wechatRetObj.getErrno().equals(0) && wechatRetObj.getData() != null) {
                String prepaidId = ((WeChatPayPrepayRetVo) wechatRetObj.getData()).getPrepayId();
                prePaymentRetVo.setPrepaidId(prepaidId);
            }
        } else if (paymentVo.getPatternId() == ALI) {
            AliPayVo aliPayVo = new AliPayVo(tradeSn, paymentVo.getAmount());
            String bizContent = JacksonUtil.toJson(aliPayVo);
            alipayService.gatewayDo(AlipayConfig.APP_ID, "alipay.trade.wap.pay", AlipayConfig.FORMAT,
                    AlipayConfig.CHARSET, AlipayConfig.SIGN_TYPE, AlipayConfig.SIGN, AlipayConfig.TIMESTAMP, AlipayConfig.NOTIFY_URL, bizContent);
        }
        return new ReturnObject(prePaymentRetVo);
    }

    //微信统一下单接口的传入信息
    public WeChatPayTransactionVo getWeChatPayVo(Integer total) {
        WeChatPayTransactionVo weChatPayTransactionVo = new WeChatPayTransactionVo();
        weChatPayTransactionVo.setAppid("wxd678efh567hg6787");
        weChatPayTransactionVo.setMchid("1230000109");
        weChatPayTransactionVo.setDescription("pay");
        weChatPayTransactionVo.setTimeExpire(LocalDateTime.now());
        weChatPayTransactionVo.setAmount(new TransactionAmountVo(total, "CNY"));
        weChatPayTransactionVo.setPayer(new PayerVo("oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"));
        weChatPayTransactionVo.setNotifyUrl("/wechat/payment/notify");
        return weChatPayTransactionVo;
    }

    /**
     * 对账
     * 第三方支付下载账单接口未实现，使用orderSn查询每一笔第三方支付信息
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject reconciliation(LocalDateTime beginTime, LocalDateTime endTime, Long userId, String userName) {
        ReconciliationRetVo reconciliationRetVo = new ReconciliationRetVo(0, 0, 0);
        return new ReturnObject(reconciliationRetVo);
    }

//===================================================== 支付或退款通知 =====================================

    /**
     * 微信支付通知
     */
    @Transactional(rollbackFor = Exception.class)
    public PaymentReturnObject wechatPaymentNotify(PaymentNotifyRetVo paymentNotifyVo, Long userId, String userName) {
        //如果已经通知过，直接返回成功
        WeChatPayTransactionRetVo transactionRetVo = paymentNotifyVo.getResource().getCiphertext();
        String outTradeNo = transactionRetVo.getOutTradeNo();
        Payment payment = (Payment) paymentDao.selectPaymentByTradeSn(outTradeNo).getData();
        if (payment == null || !payment.getState().equals(Payment.State.OBLIGATION.getCode()))
            return new PaymentReturnObject(PaymentReturnNo.SUCCESS);
        //设置支付状态
        String state = transactionRetVo.getTradeState();
        if (state.equals(TRADE_STATE_SUCCESS)) {
            setOrderStateSuccess(payment.getDocumentId());
            payment.setState(Payment.State.PAID.getCode());
        } else {
            payment.setState(Payment.State.FAILED.getCode());
        }
        Common.setPoModifiedFields(payment, userId, userName);
        ReturnObject paymentRet = paymentDao.updatePayment(payment);
        if (paymentRet.getCode().getCode() != 0) {
            return new PaymentReturnObject(PaymentReturnNo.FAIL);
        }
        return new PaymentReturnObject(PaymentReturnNo.SUCCESS);
    }

    /**
     * 微信退款通知
     */
    @Transactional(rollbackFor = Exception.class)
    public PaymentReturnObject WechatRefundNotify(RefundNotifyRetVo refundNotifyRetVo) {
        //如果已经通知过，直接返回成功
        RefundNotifyRetVo.Resource.Ciphertext ciphertext = refundNotifyRetVo.getResource().getCiphertext();
        String outTradeNo = ciphertext.getOutTradeNo();
        Refund refund = (Refund) refundDao.selectRefundByTradeSn(outTradeNo).getData();
        if (refund == null || !refund.getState().equals(Refund.State.OBLIGATION.getCode()))
            return new PaymentReturnObject(PaymentReturnNo.SUCCESS);
        //设置退款状态
        String state = ciphertext.getRefundStatus();
        if (state.equals(TRADE_STATE_SUCCESS)) {
            refund.setState(Refund.State.PAID.getCode());
        } else {
            refund.setState(Refund.State.FAILED.getCode());
        }
        ReturnObject refundRet = refundDao.updateRefund(refund);
        if (refundRet.getCode().getCode() != 0) {
            return new PaymentReturnObject(PaymentReturnNo.FAIL);
        }
        return new PaymentReturnObject(PaymentReturnNo.SUCCESS);
    }

    /**
     * 阿里异步支付通知
     */
    @Transactional(rollbackFor = Exception.class)
    public PaymentReturnObject aliPaymentNotify(NotifyBody notifyBody) {
        //如果已经通知过，直接返回成功
        String outTradeNo = notifyBody.getOut_trade_no();
        Payment payment = (Payment) paymentDao.selectPaymentByTradeSn(outTradeNo).getData();
        if (payment == null || !payment.getState().equals(Payment.State.OBLIGATION.getCode()))
            return new PaymentReturnObject(PaymentReturnNo.SUCCESS);
        //设置支付状态
        String state = notifyBody.getTrade_status();
        if (state.equals(TRADE_STATE_SUCCESS)) {
            setOrderStateSuccess(payment.getDocumentId());
            payment.setState(Payment.State.PAID.getCode());
        } else {
            payment.setState(Payment.State.FAILED.getCode());
        }
        ReturnObject paymentRet = paymentDao.updatePayment(payment);

        if (paymentRet.getCode().getCode() != 0) {
            return new PaymentReturnObject(PaymentReturnNo.FAIL);
        }
        return new PaymentReturnObject(PaymentReturnNo.SUCCESS);
    }

    public void setOrderStateSuccess(String documentId) {
        Order order = (Order) orderDao.selectOrderByDocumentId(documentId).getData();
        order.setState(Order.State.PAID.getCode());
        orderDao.updateOrder(order);

        List<Order> orders = (List<Order>) orderDao.selectChildOrders(order.getId()).getData();
        for (Order order1 : orders) {
            order1.setState(Order.State.PAID.getCode());
            orderDao.updateOrder(order1);
        }
    }

    /**
     * 查询自己订单的支付信息
     *
     * @param id
     * @return ReturnObject
     */
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getOrderPayments(Long id) {
        PaymentPoExample paymentPoExample = new PaymentPoExample();
        PaymentPoExample.Criteria criteria = paymentPoExample.createCriteria();
        criteria.andDocumentIdEqualTo(String.valueOf(id));

        return paymentDao.getOrderPayments(paymentPoExample);
    }

    /**
     * 获得支付渠道的所有状态
     *
     * @return ReturnObject
     */
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getAllPatternStates() {
        return paymentDao.getAllPatternStates();
    }


    /**
     * 获取退款单的所有状态
     *
     * @return ReturnObject
     */
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getAllRefundStates() {
        return refundDao.getAllRefundStates();
    }


    /**
     * 获得支付单的所有状态
     *
     * @return ReturnObject
     */
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getAllPaymentsStates() {
        return paymentDao.getAllPaymentsStates();
    }

    /**
     * 获得所有的支付渠道
     *
     * @return ReturnObject
     */
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getPayPatterns() {

        PaymentPoExample paymentPoExample = new PaymentPoExample();
        PaymentPoExample.Criteria criteria = paymentPoExample.createCriteria();

        return paymentDao.getPayPatterns(paymentPoExample);
    }

    /**
     * 获得当前有效的支付渠道
     *
     * @return ReturnObject
     */
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getAvailablePatterns() {

        PaymentPattern paymentPattern = new PaymentPattern();


        PaymentPatternPoExample paymentPatternPoExample = new PaymentPatternPoExample();
        PaymentPatternPoExample.Criteria criteria = paymentPatternPoExample.createCriteria();
        criteria.andStateEqualTo(PaymentPattern.State.available.getCode());
        return paymentDao.getAvailablePatterns(paymentPatternPoExample);
    }


    /**
     * 新建退款单
     *
     * @param refund
     * @return
     */
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject insertinsertRefund(Refund refund) {
        return new ReturnObject(refundDao.insertRefund(refund));
    }


}
